package eip.chapter4.invalidmessage.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IMarshallingContext;
import org.jibx.runtime.JiBXException;

import eip.chapter4.invalidmessage.Hotel;
import eip.chapter4.invalidmessage.HotelSearchMessage;

public class SearchServiceFacade {

	/**
	 * Search hotels
	 */
	public OMElement searchHotels(OMElement element) throws Exception {

		// transform the incoming message to a java object
		IBindingFactory bfact = BindingDirectory
				.getFactory(HotelSearchMessage.class);
		HotelSearchMessage msg = (HotelSearchMessage) bfact
				.createUnmarshallingContext().unmarshalDocument(
						new StringReader(element.toString()), null);

		// invoke the service
		HotelSearchServiceImpl service = new HotelSearchServiceImpl();
		List<Hotel> hotels = service.searchHotels(msg);

		// transform the result back to XML
		String result = transform(hotels);
		XMLStreamReader parser = XMLInputFactory.newInstance()
				.createXMLStreamReader(new StringReader(result));
		StAXOMBuilder builder = new StAXOMBuilder(parser);
		
		return builder.getDocumentElement();
	}

	/**
	 * Transform a list of hotels to XML
	 */
	private String transform(List<Hotel> hotels) throws JiBXException,
			DocumentException, IOException {

		Document doc = DocumentFactory.getInstance().createDocument();
		Element root = doc.addElement("processResponse");

		StringWriter output = new StringWriter();
		IBindingFactory bfact = BindingDirectory
				.getFactory(HotelSearchMessage.class);
		IMarshallingContext mctx = bfact.createMarshallingContext();
		for (Hotel hotel : hotels) {
			ByteArrayOutputStream bOut = new ByteArrayOutputStream();
			mctx.marshalDocument(hotel, "UTF-8", null, bOut);
			SAXReader reader = new SAXReader();
			Document hotelDoc = reader.read(new ByteArrayInputStream(bOut
					.toByteArray()));
			root.add(hotelDoc.getRootElement());
		}
		new XMLWriter(output).write(root);
		return output.toString();
	}
}
